package com.hyl.auth.config.security;

import com.hyl.auth.config.security.filter.CheckTokenFilter;
import com.hyl.auth.config.security.handler.AnonymousAuthenticationHandler;
import com.hyl.auth.config.security.handler.CustomerAccessDeniedHandler;
import com.hyl.auth.config.security.handler.LoginFailureHandler;
import com.hyl.auth.config.security.handler.LoginSuccessHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * @Description TODO
 * @Author hyl
 * @Date 2023/6/20 13:45
 **/
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
	@Resource
	private CustomerUserDetailsService customerUserDetailsService;//登入用户信息
	@Resource
	private LoginSuccessHandler loginSuccessHandler;//登录认证成功处理器类
	@Resource
	private LoginFailureHandler loginFailureHandler;//登录认证失败处理器类
	@Resource
	private AnonymousAuthenticationHandler anonymousAuthenticationHandler;//匿名用户访问资源处理器
	@Resource
	private CustomerAccessDeniedHandler customerAccessDeniedHandler;//认证用户访问无权限资源时处理器

	@Resource
	private CheckTokenFilter checkTokenFilter;//token验证过滤器

	/**
	 * 定义SpringSecurity密码加密对象
	 * @Bean 注解通常会在@Configuration注解描述的类中描述方法,
	 * 用于告诉spring框架这个方法的返回值会交给spring管理,并spring
	 * 管理的这个对象起个默认的名字,这个名字与方法名相同,当然也可以通过
	 * @Bean注解起名字
	 */
	@Bean //对象名默认为方法名
	public BCryptPasswordEncoder passwordEncoder(){
		return new BCryptPasswordEncoder();
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		//登录前进行过滤
		http.addFilterBefore(checkTokenFilter, UsernamePasswordAuthenticationFilter.class);
		//登入
		http.formLogin()
				//设置登陆请求处理地址(对应form表单中的action),登陆时会访问UserDetailService对象
				.loginProcessingUrl("/api/user/login")
				//设置请求用户名参数为username(默认就是username，可以自己修改，需要与表单同步)
				.usernameParameter("username")
				//请求请求密码参数为password(默认就是password，可以自己修改，需要与表单同步)
				.passwordParameter("password")
				// 设置登录验证成功或失败后的的跳转地址
				.successHandler(loginSuccessHandler) //认证成功
				.failureHandler(loginFailureHandler) //认证失败
				// 禁用csrf防御机制
			.and().csrf().disable()
				.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
			.and()//设置请求的授权
				.authorizeRequests()
				.antMatchers("/user/login").permitAll()
				.anyRequest().authenticated()
			.and() //自定义异常处理对象
				.exceptionHandling()
				.authenticationEntryPoint(anonymousAuthenticationHandler)
				.accessDeniedHandler(customerAccessDeniedHandler)
			.and().cors();//开启跨域配置
	}

	/**
	 * 配置认证处理器
	 * @param auth
	 * @throws Exception
	 */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception
	{
		auth.userDetailsService(customerUserDetailsService).passwordEncoder(passwordEncoder());
	}
}